
#ifndef XMLTREE_H
#define XMLTREE_H


#include "xercesc/dom/DOM.hpp"
#include "XmlDefs.h"
#include "XmlParser.h"
#include "TCL/sequential_tree.h"
#include <boost/shared_ptr.hpp>

#include <map>
#include <sstream>

namespace awa {
  
  enum IndexParserOptions
  {
    
    VALIDATION            = 0,
    
    DOMNAMESPACES         = 1,
    
    SCHEMA                = 2,
    
    SCHEMAFULLCHECKING    = 3,
    
    DATATYPENORMALIZATION = 4,
    
    CACHEGRAMMARFROMPARSE = 5
    
  };
  
  typedef std::vector<IndexParserOptions>  ParserOptions;
  
  const XMLCh* MapToXercesParserOptions( IndexParserOptions );

  std::vector<IndexParserOptions> getParserSupportedFeatures();

  template< class XmlNode > struct Node;
  
  typedef Node< DOMNode >     XercesDOMNode;
  
  typedef tcl::sequential_tree<XercesDOMNode> AbstractTree;
  
  template< class XmlNode >
    struct Node {
      
      typedef XmlNode            value_type;
      typedef value_type*        pointer;
      typedef value_type* const  const_pointer;

      Node() { }
      
    Node(const DOMNode* n) : ptrDOMNode( const_pointer(n) ) 
      { 
	if( n->getNodeName() )
	  nodename = XtoStr( n->getNodeName() );
	if( n->getNodeValue() )
	  nodevalue = XtoStr( n->getNodeValue() );
	if( n->getNamespaceURI() )
	  namespaceuri = XtoStr( n->getNamespaceURI() );
	if( n->getPrefix() )
	  prefx = XtoStr( n->getPrefix() );
	if( n->getLocalName() )
	  localname = XtoStr( n->getLocalName() );
	if( n->getBaseURI() )
	  baseuri = XtoStr( n->getBaseURI() );
	
	type = static_cast<typename XmlNode::NodeType >( n->getNodeType() );
    }
      
      inline Node& operator = (const Node& rhs) {
	ptrDOMNode = rhs.ptrDOMNode;
	nodename = rhs.nodename;
	nodevalue = rhs.nodevalue;
	namespaceuri = rhs.namespaceuri;
	prefx = rhs.prefx;
	localname = rhs.localname;
	baseuri = rhs.baseuri;
	type = rhs.type;
      }
	
      typename Node::const_pointer ptrDOMNode;
      std::string nodename;
      std::string nodevalue;
      std::string namespaceuri;
      std::string prefx;
      std::string localname;
      std::string baseuri;
      typename XmlNode::NodeType type;
    };
  
  
  class XercesNodeFilter : public DOMWriterFilter {
    
  public :
    
    typedef unsigned long     NodeType;
    
    typedef unsigned long     FilterRule;
    
    typedef boost::shared_ptr< std::map<NodeType, FilterRule> > FilterLookupTable;
    
  XercesNodeFilter(unsigned long filterOpts)
    : opts(filterOpts) {}
    
  XercesNodeFilter(const XercesNodeFilter& src)
    :opts( src.getWhatToShow() ) {}
    
    XercesNodeFilter()
    : opts( SHOW_ALL ) {}

    ~XercesNodeFilter(){}
    
    virtual short acceptNode(const DOMNode* n) const;
    
    virtual unsigned long getWhatToShow() const ;
    
    virtual void setWhatToShow(unsigned long);
    
  private:
    
    XercesNodeFilter& operator = (const XercesNodeFilter&);
    
    unsigned long opts;
    
    static FilterLookupTable Filters;
    
  };
  
  
  inline unsigned long
    XercesNodeFilter::getWhatToShow() const {
    
    return opts;
    
  }
  
  inline void 
    XercesNodeFilter::setWhatToShow(unsigned long toShow) {
    
    opts = toShow;
    
  }
  
  class XercesException : 
  public DOMException, 
    virtual public std::exception {
    
  public:
  XercesException(DOMException::ExceptionCode c, const XMLCh& m, const char* filename, unsigned line)
    : code( c ), 
      msg( m ), 
      inFile( filename ), 
      atLine( line )
      {}
    
    XMLCh getMessage() const;
    
    DOMException::ExceptionCode getCode() const;
    
    virtual const char* what() const throw();
    
    virtual ~XercesException() throw() {}
    
  protected:
    
    XMLCh msg;
    
    DOMException::ExceptionCode code;
    
    std::string inFile;
    unsigned    atLine;
  };
  
  inline XMLCh
    XercesException::getMessage() const {
    
    return msg;
    
  }
  
  inline const char*
    XercesException::what() const throw() {
    
    std::stringstream errorMsg;
    XMLCh parserMsg( getMessage() );

    errorMsg << "[" << inFile << ":" << atLine << "]";
    errorMsg << XtoStr( &parserMsg );
    
    return errorMsg.str().c_str();
  }
  
  inline DOMException::ExceptionCode
    XercesException::getCode() const {
    
    return code;
    
  }


  // Transfer DOM to a STL like tree 
  AbstractTree*
    copyDOM(DOMNode* node, awa::XercesNodeFilter filter);
  
};

#endif
